#include "ssm2_export.h"
#include "Threshold.h"
#include "SocketService.h"
#include "msg_type.h"
#include "sendbuf.h"
#include "ResLock.h"
#include "SystemIO.h"
#include "log.h"

#include "openssl/rsa.h"
#include "openssl/crypto.h"
#include "openssl/x509.h"
#include "openssl/pem.h"
#include "openssl/ssl.h"
#include "openssl/err.h"
#include "openssl/rand.h" 
#include "openssl/bio.h"

#include "tcp_ssl.h"

#ifdef _MSC_VER
#pragma comment (lib,"ws2_32.lib")
#else
#endif	

#define MAXBUFFERSIZE 256
ResLock lkLog;

#define MBEDTLS_MPI_CHK(f) do { if( ( ret = f ) != 0 ) goto cleanup; } while( 0 )

#ifdef __cplusplus
extern "C" {
#endif

	extern INITCONF g_conf;
    
#ifdef __cplusplus
}
#endif


static int data_trans(unsigned char *senddata, unsigned int senddataLen, unsigned char *revdata, unsigned int *revdataLen)
{
	int ret = 0;
	SocketService server;
	int connectfd;

	//¡¥Ω”∑˛ŒÒ∂À
	connectfd = server.createClient(IPPROTO_TCP, g_conf.ip, g_conf.port);
	if (connectfd <= 0)
	{
		LOG_ERROR("ERROR:The return value of server.createClient, connectfd = %08x", connectfd);
		goto ERR;
	}

	//∑¢ÀÕ ˝æ›
	ret = server.sendMsg(connectfd, (char *)senddata, senddataLen, g_conf.timeout);
	if (ret != senddataLen)
	{
		LOG_ERROR("ERROR:The return value of server.sendMsg is %08x", ret);
		goto ERR;
	}

	LOG_DEBUG("DEBUG:g_conf.timeout = %d", g_conf.timeout);


	//Ω” ’ ˝æ›
	*revdataLen = server.recvMsg(connectfd, (char *)revdata, MAXBUFFERSIZE, g_conf.timeout);
	if (*revdataLen <= 0 || *revdataLen > MAXBUFFERSIZE)
	{
		LOG_ERROR("ERROR:The return value of server.recvMsg is %08x", *revdataLen);
		goto ERR;
	}

	//πÿ±’tcp¡¨Ω”
	if (connectfd > 0)
		server.closeSocket(connectfd);

	return R_SUCCESS;

ERR:
	//πÿ±’tcp¡¨Ω”
	if (connectfd > 0)
		server.closeSocket(connectfd);
	return R_FAILURE;
}

static int data_trans_ssl(unsigned char *senddata, unsigned int senddataLen, unsigned char *revdata, unsigned int *revdataLen)
{
	int ret = 0;
	SocketService server;
	int connectfd;
    DEALSOCKET dealsocket = {0};

	//gen connected fd
	connectfd = server.createClient(IPPROTO_TCP, g_conf.ip, g_conf.port);
	if (connectfd <= 0)
	{
		LOG_ERROR("ERROR:The return value of server.createClient connectfd = %08x", connectfd);
		goto ERR;
	}

    //gen ssl socket
    ret = client_GenDealSocket(&dealsocket, connectfd, g_conf.ssltype);
    if (ret)
    {
        goto ERR;
    }

	//ssl∑¢ÀÕ ˝æ›
	//ret = SSL_write(dealsocket.ssl, senddata, senddataLen);
	ret = SSL_sendMsg(dealsocket, (char *)senddata, senddataLen, g_conf.timeout);
	if (ret != senddataLen)
	{
		goto ERR;
	}

	//sslΩ” ’ ˝æ›
	//*revdataLen = SSL_read(dealsocket.ssl, revdata, MAXBUFFERSIZE);
	*revdataLen = SSL_recvMsg(dealsocket, (char *)revdata, MAXBUFFERSIZE, g_conf.timeout);
	if (*revdataLen <= 0 || *revdataLen > MAXBUFFERSIZE)
	{
		goto ERR;
	}
    
    FreeDealSocket(&dealsocket);
	return R_SUCCESS;

ERR:
    FreeDealSocket(&dealsocket);
	return R_FAILURE;
}

int ssm2_genkey(unsigned char *id, unsigned int idlen, mbedtls_ecp_group *grp, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng,
				unsigned char *d, unsigned char *X, unsigned char *Y)
{
	int ret;
	unsigned char senddata[MAXBUFFERSIZE];
	unsigned int senddataLen = 0;
	unsigned char revdata[MAXBUFFERSIZE];
	unsigned int revdataLen = 0;

	unsigned char Xc_gen[64] = { 0 };
	unsigned char Yc_gen[64] = { 0 };
	unsigned char Xs_gen[32] = { 0 };
	unsigned char Ys_gen[32] = { 0 };
	unsigned char ds_gen[32] = { 0 };

	LOG_DEBUG("DEBUG: ssm2_genkey begin");

	//øÕªß∂À…˙≥…ÀΩ‘øº∞π˝≥Ã≤Œ ˝
	MBEDTLS_MPI_CHK(ssm2_genkey_part1(grp, f_rng, p_rng, d, Xc_gen, Yc_gen));

	LOG_DEBUG("DEBUG: ssm2_genkey_part1 ok");

	//◊È÷Ø±®Œƒ
	MBEDTLS_MPI_CHK(ssm2_genkey_part2_msg(SSM2_GENKEY_2, idlen, id, 32, Xc_gen, 32, Yc_gen, &senddataLen, senddata));

	LOG_DEBUG("DEBUG: ssm2_genkey_part2_msg ok");

	//∑¢ÀÕ∑˛ŒÒ∂À£¨≤¢Ω” ’∑µªÿ ˝æ›
	if(g_conf.ssltype == 0)
		MBEDTLS_MPI_CHK(data_trans(senddata, senddataLen, revdata, &revdataLen));
	else
		MBEDTLS_MPI_CHK(data_trans_ssl(senddata, senddataLen, revdata, &revdataLen));

	LOG_DEBUG("DEBUG: data_trans ok");
	
	//Ω‚Œˆ∑µªÿ±®Œƒ,
	MBEDTLS_MPI_CHK(ssm2_genkey_part2_parse(SSM2_GENKEY_2, revdata, revdataLen, X, Y));

	LOG_DEBUG("DEBUG: ssm2_genkey_part2_parse ok");

	
	LOG_DEBUG("DEBUG: ssm2_genkey end");
cleanup:
	return ret;
}

int ssm2_sign(unsigned char *id, unsigned int idlen,  mbedtls_ecp_group *grp, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, 
			  unsigned char *hash, unsigned char *d, unsigned char *r, unsigned char *s)
{
	int ret;
	unsigned char senddata[MAXBUFFERSIZE];
	unsigned int senddataLen = 0;
	unsigned char revdata[MAXBUFFERSIZE];
	unsigned int revdataLen = 0;

	unsigned char kc_sign[32] = { 0 };
	unsigned char Xc_sign[32] = { 0 };
	unsigned char Yc_sign[32] = { 0 };
	unsigned char ss1_sign[32] = { 0 };
	unsigned char ss2_sign[32] = { 0 };
	unsigned int r_sign_len, ss1_sign_len, ss2_sign_len;

	//«©√˚µ⁄“ª≤Ω
	MBEDTLS_MPI_CHK(ssm2_sign_step1(grp, f_rng, p_rng, kc_sign, Xc_sign, Yc_sign));
	
	//◊È÷Ø±®Œƒ
	MBEDTLS_MPI_CHK(ssm2_sign_step2_msg(SSM2_SIGN_2, idlen, id, 32, Xc_sign, 32, Yc_sign, 32, hash, &senddataLen, senddata));

	//∑¢ÀÕ∑˛ŒÒ∂À£¨≤¢Ω” ’∑µªÿ ˝æ›
	if(g_conf.ssltype == 0)
		MBEDTLS_MPI_CHK(data_trans(senddata, senddataLen, revdata, &revdataLen));
	else
		MBEDTLS_MPI_CHK(data_trans_ssl(senddata, senddataLen, revdata, &revdataLen));

	//Ω‚Œˆ∑µªÿ±®Œƒ,
	MBEDTLS_MPI_CHK(ssm2_sign_step2_parse(SSM2_SIGN_2, revdata, revdataLen, &r_sign_len, r, &ss1_sign_len, ss1_sign, &ss2_sign_len, ss2_sign));

	//«©√˚µ⁄»˝≤ø
	MBEDTLS_MPI_CHK(ssm2_sign_step3(grp, d, kc_sign, r, ss1_sign, ss2_sign, s));


cleanup:
	return ret;
}

int ssm2_decrypt(unsigned char *id, unsigned int idlen, mbedtls_ecp_group *grp, unsigned char *d, unsigned char *input, unsigned int ilen, unsigned char *output, unsigned int *olen)
{
	int ret;
	unsigned char senddata[MAXBUFFERSIZE];
	unsigned int senddataLen = 0;
	unsigned char revdata[MAXBUFFERSIZE];
	unsigned int revdataLen = 0;

	unsigned char XC1_enc[32] = { 0 };
	unsigned char YC1_enc[32] = { 0 };
	unsigned char XT1_enc[32] = { 0 };
	unsigned char YT1_enc[32] = { 0 };
	unsigned char XT2_enc[32] = { 0 };
	unsigned char YT2_enc[32] = { 0 };

	//Ω‚√‹µ⁄“ª≤Ω
	MBEDTLS_MPI_CHK(ssm2_decrypt_step1(grp, input, d, XC1_enc, YC1_enc, XT1_enc, YT1_enc));

	//◊È÷Ø±®Œƒ
	MBEDTLS_MPI_CHK(ssm2_decrypt_step2_msg(SSM2_DECRYPT_2, idlen, id, 32, XT1_enc, 32, YT1_enc, &senddataLen, senddata));

	//∑¢ÀÕ∑˛ŒÒ∂À£¨≤¢Ω” ’∑µªÿ ˝æ›
	if(g_conf.ssltype == 0)
		MBEDTLS_MPI_CHK(data_trans(senddata, senddataLen, revdata, &revdataLen));
	else
		MBEDTLS_MPI_CHK(data_trans_ssl(senddata, senddataLen, revdata, &revdataLen));

	//Ω‚Œˆ∑µªÿ±®Œƒ
	MBEDTLS_MPI_CHK(ssm2_decrypt_step2_parse(SSM2_DECRYPT_2, revdata, revdataLen, XT2_enc, YT2_enc));

	//Ω‚√‹µ⁄»˝≤Ω
	MBEDTLS_MPI_CHK(ssm2_decrypt_step3(grp, XC1_enc, YC1_enc, XT2_enc, YT2_enc, input, ilen, output, olen));

cleanup:
	return ret;
}

//”ÎmbedTLSø‚÷–µƒ∫Ø ˝÷ÿ√˚£¨ÃÌº”"_"«¯∑÷
int ssm2_compute_key_(unsigned char *id, unsigned int idlen, mbedtls_ecp_group *grp,
					  unsigned char *XRb, unsigned char *YRb, unsigned char *XPb,unsigned char *YPb, unsigned char *XRa, unsigned char *YRa, unsigned char *dc,
					  unsigned char *Xskey, unsigned char *Yskey,
					  int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
{
	int ret;
	unsigned char senddata[MAXBUFFERSIZE] = {0};
	unsigned int senddataLen = 0;
	unsigned char revdata[MAXBUFFERSIZE] = {0};
	unsigned int revdataLen = 0;

	unsigned char rA1[32*2] = { 0 };
	unsigned char t[64 * 2] = { 0 };
	unsigned char i[64 * 2] = { 0 };
	size_t t_len = 0;
	size_t rA1_len = 0;
	unsigned int XRalen = 0;
	unsigned int YRalen = 0;
	size_t i_len = 0;

	//–≠…Ãµ⁄“ª≤Ω
	MBEDTLS_MPI_CHK(ssm2_computekey_step1(grp, f_rng, p_rng, dc, rA1, &rA1_len, t, &t_len));

	//–≠…Ãµ⁄∂˛≤Ω£¨◊È÷Ø±®Œƒ//∑¢ÀÕ∑˛ŒÒ∂À£¨≤¢Ω” ’∑µªÿ ˝æ›//Ω‚Œˆ∑µªÿ±®Œƒ
	MBEDTLS_MPI_CHK(ssm2_computekey_step2_msg(SSM2_COMPUTEKEY_2, idlen, id, t_len, t, &senddataLen, senddata));
	MBEDTLS_MPI_CHK(data_trans(senddata, senddataLen, revdata, &revdataLen));
	MBEDTLS_MPI_CHK(ssm2_computekey_step2_parse(SSM2_COMPUTEKEY_2, revdata, revdataLen, &XRalen, XRa, &YRalen, YRa));

	//–≠…Ãµ⁄»˝≤Ω
	MBEDTLS_MPI_CHK(ssm2_computekey_step3(grp, rA1, rA1_len, XRa, YRa, XRb, YRb, i, &i_len));

	//–≠…Ãµ⁄Àƒ≤Ω£¨◊È÷Ø±®Œƒ//∑¢ÀÕ∑˛ŒÒ∂À£¨≤¢Ω” ’∑µªÿ ˝æ›//Ω‚Œˆ∑µªÿ±®Œƒ
	MBEDTLS_MPI_CHK(ssm2_computekey_step4_msg(SSM2_COMPUTEKEY_4, idlen, id, i_len, i, &senddataLen, senddata));
	MBEDTLS_MPI_CHK(data_trans(senddata, senddataLen, revdata, &revdataLen));
	MBEDTLS_MPI_CHK(ssm2_computekey_step4_parse(SSM2_COMPUTEKEY_4, revdata, revdataLen, (unsigned int *)&i_len, i));

	//–≠…Ãµ⁄ŒÂ≤Ω
	MBEDTLS_MPI_CHK(ssm2_computekey_step5(grp, dc, i, i_len, XRa, YRa, XPb, YPb, XRb, YRb, Xskey, Yskey));

cleanup:
	return ret;
}

